package com.zzr.demo.redis.service.impl;

import com.zzr.demo.redis.service.LockService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import sun.awt.datatransfer.ToolkitThreadBlockedHandler;

import javax.annotation.Resource;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author: xiaomi
 * @date: 2021/10/7
 * @description: 使用 字符串实现的简易版 Redis 分布式锁：
 * 一分钟解锁；
 * 缺点：
 * 1. 没有使用看门狗续期；
 * 2. 解锁非原子性
 */
@Service
@Slf4j
public class StringLockServiceImpl implements LockService {

    /**
     * 本 service 使用的独占锁的名称
     */
    private final String LOCK_NAME = "lock::locking";
    ThreadLocal<String> threadLocal = new ThreadLocal<>();

    @Resource
    StringRedisTemplate stringRedisTemplate;

    @Override
    public String lock() {
        ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();
        String lockId = UUID.randomUUID().toString();
        log.info("lock id:{}", lockId);
        Boolean ifSet = valueOperations.setIfAbsent(LOCK_NAME, lockId, 5, TimeUnit.MINUTES);
        if (ifSet) {
            //如果设置成功
            threadLocal.set(lockId);
            return lockId;
        }
        return "";
    }

    @Override
    public void unlock() {
        ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();
        String value = valueOperations.get(LOCK_NAME);
        String lockId = threadLocal.get();
        if (lockId.equals(value)) {
            //说明正是自己这把锁
            stringRedisTemplate.delete(LOCK_NAME);
        }
    }
}
